package cm

import (
	"math/big"
	"time"

	"gitee.com/law-api/cm/client"
	"gitee.com/law-api/log"
	"github.com/PicoChain/common"
	"github.com/PicoChain/types"
)

func chargeToken(amount float64) *big.Int {
	//float64 to int64
	integerAmount := int64(amount * 1e3)
	newToken := new(big.Int).SetInt64(integerAmount)

	//base eth
	baseToken := new(big.Int).SetInt64(1e15)

	return new(big.Int).Mul(newToken, baseToken)
}

func (cm *ClientManager) Charge(addr string, amount float64, timeout int) error {

	//allow account to alive in picoChain
	_, c := cm.randomClient()

	//charge money
	toAddr := common.HexToAddress(addr)
	tx, err := cm.chargeMoney(toAddr, chargeToken(amount), c)
	if err != nil {
		return err
	}

	//wait
	failed := 0
	for i := 0; i < timeout; i++ {
		if err := cm.waitMined(c, tx, 3*time.Minute); err != nil {
			failed++
			time.Sleep(1 * time.Second)
			continue
		}
		break
	}
	//if timeout, make sure transaction in pending pool
	if failed >= timeout {
		return ErrTxTimeout
	}
	return nil
}

//ClearChargeNonce clear the nonce of charge account in cache
func (cm *ClientManager) ClearChargeNonce() {
	cm.userMux.Lock()
	defer cm.userMux.Unlock()

	delete(cm.userNonces, cm.chargeAcc.From)
}

//chargeMoney give a new account some eth for operating in the picoChain.
func (cm *ClientManager) chargeMoney(to common.Address, amount *big.Int, c *client.Client) (*types.Transaction, error) {
	cm.chargeLock.Lock()
	defer cm.chargeLock.Unlock()

	//accord charge account nonce,transfer token to  accout
	nonce, err := cm.GetUserNonce(cm.chargeAcc.From)
	if err != nil {
		log.Warn("chargeAcc nonce loading failed")
		return nil, ErrAccInit
	}

	//transfer to picoChain
	tx, err := transfer(cm.chargeAcc, to, amount, nonce, c)
	if err != nil {
		log.Warn("chargeAcc tranfer", "err", err)
		return nil, ErrAccInit
	}
	log.Info("charge", "target:", c.RawUrl(), "txhash", tx.Hash().Hex())

	//update nonce
	nonce++
	cm.SetUserNonce(cm.chargeAcc.From, nonce)

	return tx, nil
}
